import dayjs from "dayjs"

/**
 * Check if an element has a class
 * @param {HTMLElement} ele
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele: HTMLElement, cls: string) {
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"))
}

/**
 * Add class to element
 * @param {HTMLElement} ele
 * @param {string} cls
 */
export function addClass(ele: HTMLElement, cls: string) {
  if (!hasClass(ele, cls)) ele.className += " " + cls
}

/**
 * Remove class from element
 * @param {HTMLElement} ele
 * @param {string} cls
 */
export function removeClass(ele: HTMLElement, cls: string) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)")
    ele.className = ele.className.replace(reg, " ")
  }
}

/**
 * 判断是否是外部链接
 *
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path: string) {
  const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path)
  return isExternal
}

/**
 * 将一维的扁平数组转换为多层级对象
 * @param  {[type]} paramData 一维数组
 * @param  {String} keyName 数组中编号id列的名称
 * @param  {String} parentKeyName 数组中父级编号pid列的名称
 * @return {[type]} treeData 多层级树状结构
 */
export function buildTree(paramData: any, keyName: string, parentKeyName: string) {
  const idMap: any = {}
  // 把所有原始数据的ID作为Key,原始数据对象作为VALUE
  paramData.forEach((item: any) => {
    idMap[item[keyName]] = item
  })

  let val: any = {}
  const treeData: Array<any> = []
  Object.keys(idMap).forEach((id) => {
    val = idMap[id]
    const pid = val[parentKeyName] || val[parentKeyName]

    if (pid === 0 || pid === "" || pid === null || pid === undefined) {
      // 如果是顶层节点，直接添加到结果集合中
      treeData.push(val)
    } else {
      // 如果不是顶层节点，找的父节点，然后添加到父节点的子节点中
      if (idMap[pid] != null) {
        if (!idMap[pid]["children"]) {
          idMap[pid]["children"] = []
        }
        idMap[pid]["children"].push(val)
      }
    }
  })

  return treeData
}

/**
 * 将一维的扁平数组转换为多层级对象
 * @param  {[type]} paramData 一维数组
 * @param  {String} keyName 数组中编号id列的名称
 * @param  {String} parentKeyName 数组中父级编号pid列的名称
 * @return {[type]} treeData 多层级树状结构
 */
export function buildTreeSelect(
  paramData: any,
  keyName: string,
  parentKeyName: string,
  valueField: string,
  labelField: string
) {
  const idMap: any = {}
  // 把所有原始数据的ID作为Key,原始数据对象作为VALUE
  paramData.forEach((item: any) => {
    idMap[item[keyName]] = Object.assign(item, {
      value: item[valueField],
      label: item[labelField],
    })
  })

  let val: any = {}
  const treeData: Array<any> = []
  Object.keys(idMap).forEach((id) => {
    val = idMap[id]
    const pid = val[parentKeyName] || val[parentKeyName]

    if (pid === 0 || pid === "" || pid === null || pid === undefined) {
      // 如果是顶层节点，直接添加到结果集合中
      treeData.push(val)
    } else {
      // 如果不是顶层节点，找的父节点，然后添加到父节点的子节点中
      if (idMap[pid] != null) {
        if (!idMap[pid]["children"]) {
          idMap[pid]["children"] = []
        }
        idMap[pid]["children"].push(val)
      }
    }
  })
  return treeData
}

/**
 * 构建下拉数据
 * @param  {[type]} paramData 一维数组
 * @param  {String} valueField 数组中编号id列的名称
 */
export function buildSelect(paramData: any, valueField: string, labelField: string) {
  const optionsData: OptionType[] = []
  // 把所有原始数据的ID作为Key,原始数据对象作为VALUE
  paramData.forEach((item: any) => {
    optionsData.push({
      value: item[valueField],
      label: item[labelField],
    })
  })
  return optionsData
}

/**
 * 时间日期转换
 * @param date 当前时间，new Date() 格式
 * @param format 需要转换的时间格式字符串
 * @description format 字符串随意，如 `YYYY-mm、YYYY-mm-dd`
 * @description format 季度："YYYY-mm-dd HH:MM:SS QQQQ"
 * @description format 星期："YYYY-mm-dd HH:MM:SS WWW"
 * @description format 几周："YYYY-mm-dd HH:MM:SS ZZZ"
 * @description format 季度 + 星期 + 几周："YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
 * @returns 返回拼接后的时间字符串
 */
export function formatDate(date: Date, format?: string): string {
  // 日期不存在，则返回空
  if (!date) {
    return ""
  }
  // 日期存在，则进行格式化
  return date ? dayjs(date).format(format ?? "YYYY-MM-DD HH:mm:ss") : ""
}

/**
 * 深度拷贝
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source: any, ignoreKeys = []) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments")
  }
  const targetObj: any = source.constructor === Array ? [] : {}
  Object.keys(source).forEach((keys) => {
    if (!ignoreKeys.includes(keys as never)) {
      if (source[keys] && typeof source[keys] === "object") {
        targetObj[keys] = deepClone(source[keys], ignoreKeys)
      } else {
        targetObj[keys] = source[keys]
      }
    }
  })
  return targetObj
}

/**
 * 深度拷贝
 * @param {Object} source
 * @returns {Object}
 */
export function deepCloneExt(source: any, ignoreData: any) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments")
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepCloneExt(source[keys], ignoreData)
    } else {
      if (!ignoreData.includes(keys)) {
        targetObj[keys] = source[keys]
      }
    }
  })
  return targetObj
}
